package abel.wlmr.model.unit;

import java.util.ArrayList;
import java.util.List;

import abel.wlmr.model.WlmrBaseUnit;
import abel.wlmr.model.WlmrException;
import abel.wlmr.model.type.Erc12Body;
import abel.wlmr.model.type.Erc14Body;
import abel.wlmr.model.type.Erc1Body;
import abel.wlmr.model.type.Erc21Body;
import abel.wlmr.model.type.Erc57Body;
import abel.wlmr.model.type.Erc60Body;
import abel.wlmr.model.type.ErcBaseBody;
import io.netty.buffer.ByteBuf;

/**
 * 曲线类数据时标 Td_c 见本附录 B.5.11.1.3.3 7
 * 正向流量示值 1 见附录 C.29 单位代号 5
 * 
 * @author Abel
 *
 */
public class AfnThirdF1_2Unit extends WlmrBaseUnit {
    private static final short ERC_60 = 60;

    private static final short ERC_57 = 57;

    private static final short ERC_21 = 21;

    private static final short ERC_14 = 14;

    private static final short ERC_12 = 12;

    private static final short ERC_1 = 1;

    private static final short MIN_LENGTH = 1 + 1 + 1 + 1;

    private short ec1;

    private short ec2;

    private short pm;

    private short pn;

    private List<ErcBaseBody> ercList = new ArrayList<>();

    public AfnThirdF1_2Unit() {
        super();
    }

    public AfnThirdF1_2Unit(short guessedLen) {
        super(guessedLen);
    }

    /* (non-Javadoc)
     * @see abel.wlmr.model.AppUnitBody#appendBuf(io.netty.buffer.ByteBuf)
     */
    @Override
    public ByteBuf appendBuf(ByteBuf buf) {
        if (pm != (pm & 0xFF) || pn != (pn & 0xFF)) {
            throw new IllegalArgumentException("pm/pn should be [0,255]");
        }
        if (pm < pn && pn - pm != ercList.size()) {
            throw new IllegalArgumentException("pn - pm should be same as size of event list");
        }
        if (pm > pn && pn - pm + 256 != ercList.size()) {
            throw new IllegalArgumentException("pn - pm + 256 should be same as size of event list");
        }

        buf.writeByte(ec1);
        buf.writeByte(ec2);
        buf.writeByte(pm);
        buf.writeByte(pn);

        for (ErcBaseBody body : ercList) {
            if (body == null) {
                throw new IllegalArgumentException("none of erc can be null");
            }

            body.appendBuf(buf);
        }

        return buf;
    }

    /* (non-Javadoc)
     * @see abel.wlmr.model.AppUnitBody#parseBuf(io.netty.buffer.ByteBuf)
     */
    @Override
    public int parseBuf(ByteBuf buf) throws WlmrException {
        if (checkBuffer(buf) < 0) {
            return -1;
        }

        ec1 = (short) (buf.readByte() & 0xFF);
        ec2 = (short) (buf.readByte() & 0xFF);
        pm = (short) (buf.readByte() & 0xFF);
        pn = (short) (buf.readByte() & 0xFF);

        short len = (short) (getGuessedLength() - MIN_LENGTH);

        for (int i = pm; i < pn; i++) {
            ByteBuf dup = buf.duplicate();
            short erc = (short) (dup.readByte() & 0xFF);
            short le = (short) (dup.readByte() & 0xFF);
            if (buf.readableBytes() < le) {
                throw new WlmrException("not enough bytes for erc");
            }

            switch (erc) {
            case ERC_1:

            {
                Erc1Body body = new Erc1Body(len);
                int plen = body.parseBuf(buf);
                if (plen < 0) {
                    throw new WlmrException("not enough bytes for erc");
                }

                len -= plen;
                ercList.add(body);

                break;
            }
            case ERC_12:

            {
                Erc12Body body = new Erc12Body(len);
                int plen = body.parseBuf(buf);
                if (plen < 0) {
                    throw new WlmrException("not enough bytes for erc");
                }

                len -= plen;
                ercList.add(body);

                break;
            }
            case ERC_14:

            {
                Erc14Body body = new Erc14Body(len);
                int plen = body.parseBuf(buf);
                if (plen < 0) {
                    throw new WlmrException("not enough bytes for erc");
                }

                len -= plen;
                ercList.add(body);

                break;
            }
            case ERC_21:

            {
                ErcBaseBody body = new Erc21Body(len);
                int plen = body.parseBuf(buf);
                if (plen < 0) {
                    throw new WlmrException("not enough bytes for erc");
                }

                len -= plen;
                ercList.add(body);

                break;
            }
            case ERC_57:

            {
                ErcBaseBody body = new Erc57Body(len);
                int plen = body.parseBuf(buf);
                if (plen < 0) {
                    throw new WlmrException("not enough bytes for erc");
                }

                len -= plen;
                ercList.add(body);

                break;
            }
            case ERC_60:

            {
                ErcBaseBody body = new Erc60Body(len);
                int plen = body.parseBuf(buf);
                if (plen < 0) {
                    throw new WlmrException("not enough bytes for erc");
                }

                len -= plen;
                ercList.add(body);

                break;
            }
            default:

            {
                ErcBaseBody body = new ErcBaseBody(len, erc, le);
                int plen = body.parseBuf(buf);
                if (plen < 0) {
                    throw new WlmrException("not enough bytes for erc");
                }

                len -= plen;
                ercList.add(body);

                break;
            }
            }
        }

        return getGuessedLength() - len;
    }

    /* (non-Javadoc)
     * @see abel.wlmr.model.WlmrDataPart#getMinLength()
     */
    @Override
    public int getMinLength() {
        return MIN_LENGTH;
    }

    /* (non-Javadoc)
     * @see abel.wlmr.model.AppUnitBody#getFinalLen()
     */
    @Override
    public short getFinalLen() {
        short len = MIN_LENGTH;

        for (ErcBaseBody body : ercList) {
            len += body.getFinalLen();
        }

        return len;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return String.format("{ec1:%s, ec2:%s, pm:%s, pn:%s, ercList:%s}", ec1, ec2, pm, pn, ercList);
    }

    /**
     * @return the ec1
     */
    public short getEc1() {
        return ec1;
    }

    /**
     * @param ec1
     *            the ec1 to set
     */
    public void setEc1(short ec1) {
        this.ec1 = ec1;
    }

    /**
     * @return the ec2
     */
    public short getEc2() {
        return ec2;
    }

    /**
     * @param ec2
     *            the ec2 to set
     */
    public void setEc2(short ec2) {
        this.ec2 = ec2;
    }

    /**
     * @return the pm
     */
    public short getPm() {
        return pm;
    }

    /**
     * @param pm
     *            the pm to set
     */
    public void setPm(short pm) {
        this.pm = pm;
    }

    /**
     * @return the pn
     */
    public short getPn() {
        return pn;
    }

    /**
     * @param pn
     *            the pn to set
     */
    public void setPn(short pn) {
        this.pn = pn;
    }

    /**
     * @return the ercList
     */
    public List<ErcBaseBody> getErcList() {
        return ercList;
    }

    /**
     * @param ercList
     *            the ercList to set
     */
    public void setErcList(List<ErcBaseBody> ercList) {
        if (ercList == null) {
            throw new IllegalArgumentException("ercList can't be null");
        }

        this.ercList = ercList;
    }
}
